package com.yimi.appstore.download2;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.yimi.appstore.YimiApplication;
import com.yimi.appstore.util.Util;

public class DownloadJob {

	private static final String TAG = "DownloadJob";
	private Context context;
	private FileService fileService;
	ExecutorService executorService = Executors.newFixedThreadPool(3);
	private ProgressBar mPb;
	private TextView mappSizeStatus;
	private TextView mdownloadPercent;
	private TextView mdownloadSpeed;
	private int threadNum = 3;
	private DownloadNotify dn;
	/* 已下载文件长度 */
	private long downloadSize = 0;

	/* 原始文件长度 */
	private long fileSize = 0;

	/* 线程数 */
	private DownLoadThread[] threads;

	/* 本地保存文件 */
	private File saveFile;

	/* 缓存各线程下载的长度 */
	private Map<Integer, Long> data = new ConcurrentHashMap<Integer, Long>();

	/* 每条线程下载的长度 */
	private long block;

	/* 下载路径 */
	private String downloadUrl;

	boolean notFinish;// 下载未完成

	private int JobStatus;

	private Handler mhandler;

	private RandomAccessFile randOut;
	
	private long beginTime ;
	

	/**
	 * 获取线程数
	 */
	public int getThreadSize() {
		return threads.length;
	}

	public void setNotFinish(boolean notFinish) {
		this.notFinish = notFinish;
	}

	/**
	 * 获取文件大小
	 * 
	 * @return
	 */
	public long getFileSize() {
		return fileSize;
	}

	/**
	 * 累计已下载大小
	 * 
	 * @param size
	 */
	protected synchronized void append(int size) {
		downloadSize += size;
		this.getDownloadEntry().setCurrentBytes(downloadSize);
		((Activity) context).runOnUiThread(new Runnable() {
			@Override
			public void run() {
				if (mPb != null) {
					mPb.setMax(100);
					Log.d(TAG, "append>>" + downloadSize * 100 / downloadEntry.getTotalBytes());
					mPb.setProgress((int) (downloadSize * 100 / downloadEntry.getTotalBytes()));
					if (JobStatus == DownloadManager.STATE_DOWNLOADING) {
						mdownloadPercent.setText("正在下载       " + (downloadSize * 100) / downloadEntry.getTotalBytes()
								+ "%");
						mappSizeStatus.setText(Util.convertStorage(downloadSize) + "/"
								+ Util.convertStorage(downloadEntry.getTotalBytes()));
						long speed = downloadSize  / (System.currentTimeMillis() - beginTime) *1000/1024  ;
						mdownloadSpeed.setText(""+speed+"k/s");
					}
				}
			}
		});

	}

	protected void clear() {
		downloadSize = 0;
		data.clear();
	}

	/**
	 * 获得该任务的下载实体
	 * 
	 * @return
	 */
	public DownloadEntity getDownloadEntry() {
		return downloadEntry;
	}

	/**
	 * 更新指定线程最后下载的位置
	 * 
	 * @param threadId
	 *            线程id
	 * @param pos
	 *            最后下载的位置
	 */
	protected synchronized void update(int threadId, long pos) {
		this.data.put(threadId, pos);
		this.fileService.update(this.downloadUrl, this.data, this.downloadEntry.getTotalBytes());
	}

	private DownloadEntity downloadEntry;

	public DownloadJob(DownloadEntity downloadEntry, Context context) {
		dn = new DownloadNotify(context);
		this.downloadEntry = downloadEntry;
		this.context = context;
		JobStatus = DownloadManager.STATE_WAITING;
		fileService = new FileService(context);
		this.downloadUrl = this.downloadEntry.getUrl();
		this.saveFile = new File(this.downloadEntry.getLocalPath());// 构建保存文件
		this.threads = new DownLoadThread[threadNum];

		Map<Integer, Long> data = new ConcurrentHashMap<Integer, Long>();
		for (int i = 0; i < threadNum; i++) {
			data.put(i + 1, (long) 0);
		}
		this.fileService.save(this.downloadUrl, data, (long) 0, this.downloadEntry.getResource(),
				this.downloadEntry.getIconUrl(), this.downloadEntry.getLocalPath(), this.downloadEntry.getMediaType());
	}

	private void initJob() {
		try {
			clear();
			URL url = new URL(this.downloadUrl);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(5 * 1000);
			conn.setRequestMethod("GET");
			conn.setRequestProperty(
					"Accept",
					"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
			conn.setRequestProperty("Accept-Language", "zh-CN");
			conn.setRequestProperty("Referer", downloadUrl);
			conn.setRequestProperty("Charset", "UTF-8");
			conn.setRequestProperty(
					"User-Agent",
					"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
			conn.setRequestProperty("Connection", "Keep-Alive");
			conn.connect();

			if (conn.getResponseCode() == 200) {
				this.fileSize = conn.getContentLength();// 根据响应获取文件大小
				if (this.fileSize <= 0)
					throw new RuntimeException("Unkown file size ");
				this.downloadEntry.setTotalBytes(this.fileSize);
				Map<Integer, Long> logdata = fileService.getData(downloadUrl);// 获取下载记录

				if (logdata.size() > 0) {// 如果存在下载记录
					for (Map.Entry<Integer, Long> entry : logdata.entrySet())
						data.put(entry.getKey(), entry.getValue());// 把各条线程已经下载的数据长度放入data中
				}

				if (this.data.size() == this.threads.length) {// 下面计算所有线程已经下载的数据长度
					for (int i = 0; i < this.threads.length; i++) {
						this.downloadSize += this.data.get(i + 1);
					}

					print("已经下载的长度" + this.downloadSize);
				}

				// 计算每条线程下载的数据长度
				this.block = (this.fileSize % this.threads.length) == 0 ? this.fileSize / this.threads.length
						: this.fileSize / this.threads.length + 1;
			} else {
				throw new RuntimeException("server no response ");
			}
		} catch (SocketTimeoutException e) {
			notifyStatus(DownloadManager.STATE_PAUSE);
			print(e.toString());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			notifyStatus(DownloadManager.STATE_ERROR);
			e.printStackTrace();
		}

	}

	public void startJob() {
		if (!Util.isConnectNetOk(context)) {
			notifyStatus(DownloadManager.STATE_ERROR);
			return;
		}
		notifyStatus(DownloadManager.STATE_READY_DOWNLOAD);
		dn.nitify();
		initJob();
		notFinish = true;
		try {
			randOut = new RandomAccessFile(this.saveFile, "rw");
			if (this.fileSize > 0)
				randOut.setLength(this.fileSize);
			randOut.close();
			URL url = new URL(this.downloadUrl);

			if (this.data.size() != this.threads.length) {
				this.data.clear();

				for (int i = 0; i < this.threads.length; i++) {
					this.data.put(i + 1, (long) 0);// 初始化每条线程已经下载的数据长度为0
				}
			}

			for (int i = 0; i < this.threads.length; i++) {// 开启线程进行下载
				Long downLength = this.data.get(i + 1);

				if (downLength < this.block && this.downloadSize < this.fileSize) {// 判断线程是否已经完成下载,否则继续下载
					this.threads[i] = new DownLoadThread(this, url, this.saveFile, this.block, this.data.get(i + 1),
							i + 1);
					this.threads[i].setPriority(7);
					executorService.execute(this.threads[i]);
				} else {
					this.threads[i] = null;
				}
			}
			notifyStatus(DownloadManager.STATE_DOWNLOADING);
			beginTime = System.currentTimeMillis();
			while (notFinish) {// 循环判断所有线程是否完成下载
				Thread.sleep(900);
				if (fileSize == downloadSize)
					notFinish = false;
			}
			if (fileSize == downloadSize) {
				YimiApplication.jobList.remove(this);
				YimiApplication.downloadHistoryList.add(downloadEntry);
				notifyStatus(DownloadManager.STATE_FINISH);
				fileService.delete(this.downloadUrl);
				fileService.saveDownloadHistory(downloadEntry.getResource(), downloadEntry.getIconUrl(),
						downloadEntry.getUrl(), downloadEntry.getLocalPath(), downloadEntry.getMediaType(),
						downloadEntry.getTotalBytes());
				this.saveFile.renameTo(new File(this.downloadEntry.getLocalPath().replace(".tmp", "")));
				Util.installApk(context, downloadEntry.getLocalPath());
				print("下载完成，删除历史记录");
			}
		} catch (Exception e) {
			print(e.toString());
		}
	}

	public void notifyStatus(int status) {
		Message msg = new Message();
		msg.what = status;
		msg.obj = JobStatus;
		mhandler.sendMessage(msg);
		JobStatus = status;
	}

	public synchronized void pauseJob() {
		notifyStatus(DownloadManager.STATE_PAUSEING);
		dn.cancle();
		try {
			if (randOut != null)
				randOut.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		for (DownLoadThread t : threads) {
			if (t != null)
				t.cancle();
		}
		notifyStatus(DownloadManager.STATE_PAUSE);
	}

	public synchronized void cancleJob() {
		dn.cancle();
		if (randOut != null)
			try {
				randOut.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		for (DownLoadThread t : threads) {
			if (t != null)
				t.cancle();
		}
		this.saveFile.delete();
		fileService.delete(this.downloadUrl);
		notifyStatus(DownloadManager.STATE_CANCLE);
	}

	/**
	 * 打印日志信息
	 * 
	 * @param msg
	 */
	private static void print(String msg) {
		Log.i(TAG, msg);
	}

	public int getJobStatus() {
		return JobStatus;
	}

	public void setJobStatus(int jobStatus) {
		JobStatus = jobStatus;
	}

	public Handler getMhandler() {
		return mhandler;
	}

	public void setMhandler(Handler mhandler) {
		this.mhandler = mhandler;
	}

	public ProgressBar getmPb() {
		return mPb;
	}

	public void setmPb(ProgressBar mPb) {
		this.mPb = mPb;
	}

	public TextView getMappSizeStatus() {
		return mappSizeStatus;
	}

	public void setMappSizeStatus(TextView mappSizeStatus) {
		this.mappSizeStatus = mappSizeStatus;
	}

	public TextView getMdownloadPercent() {
		return mdownloadPercent;
	}

	public void setMdownloadPercent(TextView mdownloadPercent) {
		this.mdownloadPercent = mdownloadPercent;
	}

	public TextView getMdownloadSpeed() {
		return mdownloadSpeed;
	}

	public void setMdownloadSpeed(TextView mdownloadSpeed) {
		this.mdownloadSpeed = mdownloadSpeed;
	}
}
